<?php

declare(strict_types=1);

namespace JsonDb\JsonDb;

/**
 * 文件处理器 - 负责JSON文件的读写和缓存管理
 * 
 * 采用单例模式管理文件缓存，确保同一文件只加载一次
 * 包含文件验证、读写操作和缓存管理功能
 */
class FileHandler
{
	/** @var string 当前处理的JSON文件路径 */
	private string $tableFile;

	/** @var array 静态文件缓存池 [文件路径 => 数据数组] */
	private static array $cache = [];

	/**
	 * 构造函数
	 * 
	 * @param string $tableFile 要处理的JSON文件完整路径
	 */
	public function __construct(string $tableFile)
	{
		$this->tableFile = $tableFile;
	}

	/**
	 * 读取并解析JSON文件内容
	 * 
	 * @return array 返回解析后的数据数组
	 * @throws Exception 文件不存在/不可读时抛出异常
	 */
	public function read(): array
	{
		// 使用缓存机制避免重复读取文件
		if (isset(self::$cache[$this->tableFile])) {
			return self::$cache[$this->tableFile];
		}

		// 验证文件状态（存在性、可读性、自动创建等）
		$this->validateFile();

		// 读取并解析JSON内容
		$rawData = file_get_contents($this->tableFile);
		$data = json_decode($rawData, true);

		// 处理JSON解析错误
		if (json_last_error() !== JSON_ERROR_NONE) {
			throw new Exception(
				"JSON 解析错误: " . json_last_error_msg() .
					" 文件: " . basename($this->tableFile)
			);
		}

		// 更新缓存并返回数据
		return self::$cache[$this->tableFile] = $data ?: [];
	}

	/**
	 * 将数据写入JSON文件
	 * 
	 * @param array $data 要写入的数据数组
	 * @throws Exception 文件不可写时抛出异常
	 */
	public function write(array $data): void
	{
		// 验证文件可写性，自动创建目录结构
		$this->validateFile(true);

		// 生成带格式的JSON数据
		$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

		// 写入文件并检查结果
		if (file_put_contents($this->tableFile, $json) === false) {
			throw new Exception("文件写入失败: " . $this->tableFile);
		}

		// 更新缓存
		self::$cache[$this->tableFile] = $data;
	}


	/**
	 * 验证文件状态
	 * 
	 * @param bool $create 当文件不存在时是否自动创建
	 * @throws Exception 文件验证失败时抛出
	 */
	private function validateFile(bool $create = false): void
	{
		// 处理文件不存在的情况
		if (!file_exists($this->tableFile)) {
			if ($create) {
				// 确保目录存在且可写
				$dir = dirname($this->tableFile);
				if (!is_dir($dir)) {
					mkdir($dir, 0755, true);
				}
				if (!is_writable($dir)) {
					throw new Exception("目录不可写: " . $dir);
				}
				// 创建初始空数组文件
				file_put_contents($this->tableFile, '[]');
			} else {
				throw new Exception("数据表不存在: " . $this->tableFile);
			}
		}

		// 检查文件权限
		if (!is_readable($this->tableFile) || !is_writable($this->tableFile)) {
			throw new Exception("文件权限不足: " . $this->tableFile);
		}
	}
}
